package com.start.shop.common.config;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
//	@SuppressWarnings("rawtypes")
//    @Bean
//    public CacheManager cacheManager(RedisTemplate redisTemplate) {
//        RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
//        //设置缓存过期时间
//        //rcm.setDefaultExpiration(60);//秒
//        return rcm;
//    }

	/*
	 * @Bean public RedisTemplate<String, Object>
	 * redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String,Object>
	 * redisTemplate =new RedisTemplate<String, Object>();
	 * redisTemplate.setConnectionFactory(factory); return redisTemplate; }
	 */

	/*
	 * @Bean public RedisTemplate<String, Object>
	 * redisTemplate(RedisConnectionFactory redisConnectionFactory) {
	 * 
	 * Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new
	 * Jackson2JsonRedisSerializer<Object>(Object.class); ObjectMapper om = new
	 * ObjectMapper(); om.setVisibility(PropertyAccessor.ALL,
	 * JsonAutoDetect.Visibility.ANY);
	 * om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
	 * jackson2JsonRedisSerializer.setObjectMapper(om); RedisTemplate<String,
	 * Object> template = new RedisTemplate<String, Object>();
	 * template.setConnectionFactory(redisConnectionFactory);
	 * template.setKeySerializer(jackson2JsonRedisSerializer);
	 * template.setValueSerializer(jackson2JsonRedisSerializer);
	 * template.setHashKeySerializer(jackson2JsonRedisSerializer);
	 * template.setHashValueSerializer(jackson2JsonRedisSerializer);
	 * template.afterPropertiesSet(); return template; }
	 */

	@Bean
	public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
		StringRedisTemplate template = new StringRedisTemplate(factory);

//        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
//        redisTemplate.setConnectionFactory(factory);
		setSerializer(template); // 设置序列化工具，这样ReportBean不需要实现Serializable接口
		template.afterPropertiesSet();
		return template;
	}

	private void setSerializer(StringRedisTemplate template) {
		// 使用Jackson2JsonRedisSerialize 替换默认的jdkSerializeable序列化
		Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);
		// 设置value的序列化规则和 key的序列化规则
		template.setValueSerializer(jackson2JsonRedisSerializer);
		// template.setKeySerializer(new StringRedisSerializer());
	}

	/**
	 * 最新版，设置redis缓存过期时间
	 */

	@Bean
	public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
		return new RedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
				this.getRedisCacheConfigurationWithTtl(60*100), // 默认策略，未配置的 key 会使用这个
				this.getRedisCacheConfigurationMap() // 指定 key 策略
		);
	}

	private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
		Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
		//SsoCache和BasicDataCache进行过期时间配置
		redisCacheConfigurationMap.put("messagCache", this.getRedisCacheConfigurationWithTtl(30 * 60));

		//自定义设置缓存时间
		redisCacheConfigurationMap.put("weixin::getAccessToken", this.getRedisCacheConfigurationWithTtl(3000));
		redisCacheConfigurationMap.put("userCache", this.getRedisCacheConfigurationWithTtl(60*10));
		redisCacheConfigurationMap.put("Shop::CouponConfig", this.getRedisCacheConfigurationWithTtl(60));
		return redisCacheConfigurationMap;
	}

	private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
		Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
				Object.class);
		ObjectMapper om = new ObjectMapper();
		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
		om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
		jackson2JsonRedisSerializer.setObjectMapper(om);
		RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
		redisCacheConfiguration = redisCacheConfiguration
				.serializeValuesWith(
						RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
				.entryTtl(Duration.ofSeconds(seconds));

		return redisCacheConfiguration;
	}

}
